package com.vhall.component.service.inav.impl;
//--------------------Optional ---------------------------
//region-plugin-ctrl-start

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vhall.component.dao.account.AccountMapper;
import com.vhall.component.dao.livecolumn.LiveColumnAttentionMapper;
import com.vhall.component.dao.room.RiskWarningMapper;
import com.vhall.component.dao.room.RoomConfigMapper;
import com.vhall.component.dao.tag.PageChannelMapper;
import com.vhall.component.entity.account.GuosenStaffEntity;
import com.vhall.component.entity.ctrl.vo.ConnectJudgeRspVO;
import com.vhall.component.entity.guosen.dto.GetTghInfoDTO;
import com.vhall.component.entity.guosen.enums.GuoXinXtgzstgGetTghInfoResponseEnum;
import com.vhall.component.entity.inav.vo.*;
import com.vhall.component.entity.livecolumn.LiveColumnAttention;
import com.vhall.component.entity.preparation.vo.GetInviteCardReqVO;
import com.vhall.component.entity.preparation.vo.GetInviteCardRespVO;
import com.vhall.component.entity.record.RecordEntityCacheDTO;
import com.vhall.component.entity.record.RecordEntityDTO;
import com.vhall.component.entity.room.RoomConfig;
import com.vhall.component.entity.room.dto.RoomJoinsEntityDTO;
import com.vhall.component.entity.room.dto.RoomWatermarkDTO;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.entity.room.entity.AnchorRoomRelationEntity;
import com.vhall.component.entity.room.entity.RiskWarningEntity;
import com.vhall.component.entity.room.enums.*;
import com.vhall.component.entity.room.vo.ApplyEntityDTO;
import com.vhall.component.entity.room.vo.RoomSupplyEntityDTO;
import com.vhall.component.entity.tag.PageChannelEntity;
import com.vhall.component.entity.thirduser.ThirdUserVO;
import com.vhall.component.entity.thirduser.enums.ThirdUserTypeEnum;
import com.vhall.component.entity.thirduser.vo.GuoxinInvestmentAdvisorTeamDTO;
import com.vhall.component.entity.watchlimit.dto.ApplyUserEntityDTO;
import com.vhall.component.entity.watchlimit.dto.WhiteAccountsEntityDTO;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.utils.CollectionUtils;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.constant.RoomConstant;
import com.vhall.component.plugin.common.enums.RoomConfigStatusEnum;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.properties.ThirdPartyProperties;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.support.VssToken;
import com.vhall.component.plugin.common.support.VssTokenThreadLocal;
import com.vhall.component.plugin.common.utils.JsonUtil;
import com.vhall.component.plugin.core.service.GuoXinService;
import com.vhall.component.plugin.core.service.PaasService;
import com.vhall.component.plugin.core.service.VssTokenService;
import com.vhall.component.service.account.GuosenStaffService;
import com.vhall.component.service.ctrl.CtrlService;
import com.vhall.component.service.inav.InfoService;
import com.vhall.component.service.interactive.DocumentsRoomService;
import com.vhall.component.service.livecolumn.LiveColumnService;
import com.vhall.component.service.preparation.InviteCardService;
import com.vhall.component.service.record.RecordInnerService;
import com.vhall.component.service.room.AnchorRoomRelationService;
import com.vhall.component.service.room.RoomInnerService;
import com.vhall.component.service.room.RoomService;
import com.vhall.component.service.tag.TagService;
import com.vhall.component.service.watchlimit.WatchLimitInnerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * @author yongzheng.xu
 * @date 2021/6/23 18:01
 */
@Slf4j
@Service
public class InfoServiceImpl implements InfoService {

    @Value("${paas.app-domain}")
    private String applicationUrl;

    @Autowired
    private CtrlService ctrlService;

    @Autowired
    private RecordInnerService recordInnerService;

    @Autowired
    private TagService tagService;

    @Autowired
    private DocumentsRoomService documentsRoomService;

    @Autowired
    private RoomInnerService roomInnerService;
    @Autowired
    private RoomService roomService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private PaasService paasService;

    @Autowired
    private VssTokenService vssTokenService;

    @Autowired
    private WatchLimitInnerService watchLimitInnerService;

    @Autowired
    private InviteCardService inviteCardService;

    @Autowired
    private PageChannelMapper pageChannelMapper;

    @Autowired
    private RoomConfigMapper roomConfigMapper;

    @Resource
    private LiveColumnAttentionMapper liveColumnAttentionMapper;

    @Resource
    private LiveColumnService liveColumnService;

    private static final List<Integer> LIMIT_TYPE = Arrays.asList(1, 2, 3);

    @Value("${paas.web-domain}")
    public String webDomain;

    @Value("${vhall.viewingPath}")
    public String viewingPath;

    @Autowired
    private RiskWarningMapper riskWarningMapper;

    /**
     * 交互时序图：http://assets.processon.com/chart_image/636cc97de401fd43fe99cfa5.png
     *
     * @param vo
     * @return
     */
    @Resource
    private AccountMapper accountMapper;
    @Override
    public InavRespVO get(GetInavVO vo) {
        if (StringUtils.isNotEmpty(vo.getRoleName())
                && !vo.getRoleName().equals(RoomConstant.HOST)
                && !vo.getRoleName().equals(RoomConstant.AUDIENCE)) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
        }
        InavRespVO result = new InavRespVO();
        RoomsEntityDTO room = new RoomsEntityDTO();
        // 兼容il_id和room_id
        if (vo.getIlId() != null) {
            String ilId = vo.getIlId().toString();
            room = roomInnerService.getRoomInfoByIlId(ilId);
        }
        if (StringUtils.isNotBlank(vo.getRoomId())) {
            String roomId = vo.getRoomId();
            room = roomInnerService.getRoomInfo(roomId);
        }
        Optional.ofNullable(room).orElseThrow(()->new BusinessException(BizErrorCode.EMPTY_ROOM));
        InavRoomRespVO liveInfo = new InavRoomRespVO();
        BeanUtils.copyProperties(room, liveInfo);

        handleDisclaimer(room, liveInfo);

        Token account = TokenThreadLocal.getToken();
        //房间的观看限制为报名模式时，查询数据库中的表单模板
        if (Objects.equals(liveInfo.getLimitType(), 1)) {
            ApplyEntityDTO apply = watchLimitInnerService.getApply(String.valueOf(vo.getIlId()));
            if (apply != null) {
                liveInfo.setFormId(String.valueOf(apply.getSourceId()));
            }
        }
        // 获取水印
        RoomWatermarkDTO roomWatermark = roomService.getRoomWatermark(room.getWatermarkTempId());
        result.setWatermark(roomWatermark);
        //对房间设置标签
        setTag(result, room);
        // 开播时长
        result.setSecond(getSecond(room));
        // 获取用户在线连接数
        //获取直播间角色  如果用户登录了  一种逻辑  没有登录一种
        if (account != null) {
            bulidInavRespVOWithAccount(result, liveInfo, account, room, vo);
            // 判断当前登录人员，是否订阅了该房间对应的栏目
            checkColumnAttention(account, liveInfo);
        } else {
            result.setStatus(String.valueOf(room.getStatus()));
        }
        // 邀请卡状态   如果你得应用里面  没有标签 可以 直接注释掉
        setRoomDetails(room, liveInfo);
        // 暖场视频
        WarmVo warmInfo = getWarmInfo(room.getIlId());
        result.setWarmInfo(warmInfo);
        if (Objects.nonNull(warmInfo) && warmInfo.getType() == 0) {
            liveInfo.setWarmType(0);
            liveInfo.setWarmVodId(null);
        }
        liveInfo.setGiftFrequency(room.getGiftFrequency());

        // 分享链接
        liveInfo.setWatchUrl(webDomain + "/live-room/watch/" + room.getIlId());

        // 分享链接,注意这里是后端额外处理过，与pc页面分享不一致。
        String type = room.getLiveType().equals(LiveRoomTypeEnum.ON_DEMAND.getType()) ? "shortVideo" : "watch";
        liveInfo.setWatchUrlApp(viewingPath + "/mobile/" + type + "/" + room.getIlId());

        liveInfo.setLiveContentTypeName(LiveContentTypeEnum.getDescription(liveInfo.getLiveContentType()));
        //是否显示开户按钮
        liveInfo.setShowOpenAccount(getShowOpenAccount(room));
//        回放审核通过的逻辑
        handleRecordInfo(liveInfo);
        List<ThirdUserVO> anchorRoomInfo = roomInnerService.getCacheRoomAnchorInfoList(room.getIlId());
        liveInfo.setAnchorInfoList(anchorRoomInfo);
        handleShowRoomStatus(result,liveInfo,room);
        result.setRoomInfo(liveInfo);

        // 邀请卡状态
        // 如果你得应用里面  没有标签 可以 直接注释掉
        if (checkInviteCard(room.getRoomId())) {
            result.setInviteStatus(1);
        } else {
            result.setInviteStatus(0);
        }
        return result;
    }



    /**
     * 免责声明处理
     * @param room
     * @param liveInfo
     */
    private void handleDisclaimer(RoomsEntityDTO room, InavRoomRespVO liveInfo) {
        LambdaQueryWrapper<RiskWarningEntity> lambdaQueryWrapper = Wrappers.lambdaQuery();
        Integer liveContentType = room.getLiveContentType();
        lambdaQueryWrapper.eq(RiskWarningEntity::getLiveContentType, liveContentType);
        lambdaQueryWrapper.last("limit 1");
        RiskWarningEntity riskWarningEntity = riskWarningMapper.selectOne(lambdaQueryWrapper);
        if (riskWarningEntity != null){
            liveInfo.setDisclaimer(riskWarningEntity.getContent());
        }
    }

    /**
     * 回放信息处理
     * @param liveInfo
     */
    private void handleRecordInfo(InavRoomRespVO liveInfo) {
        if (!Objects.equals(liveInfo.getPlaybackStatus() , 1)){
            liveInfo.setRecordId("");
        }else{
            String recordId = liveInfo.getRecordId();
            if (StrUtil.isNotBlank(recordId)) {
                RecordEntityCacheDTO record = recordInnerService.getCacheRecord(recordId);
                if (Objects.nonNull(record)) {
                    liveInfo.setPointStatus(record.getRecordChapterStatus());
                }
            }
        }
    }







    /**
     * 处理直播外部显示状态
     * @param result
     * @param liveInfo
     * @param room
     */
    private void handleShowRoomStatus(InavRespVO result, InavRoomRespVO liveInfo, RoomsEntityDTO room) {
        Integer showRoomStatus = roomInnerService.getShowRoomStatus(room);
        result.setStatus(String.valueOf(showRoomStatus));
        liveInfo.setStatus(showRoomStatus);
        liveInfo.setActualStatus(room.getStatus());
    }



    @NotNull
    private Integer getShowOpenAccount(RoomsEntityDTO room) {
        Integer showOpenAccount = 0;
        String accountVerification = room.getAccountVerification();
//        投教类产品
        if (Objects.equals(LiveContentTypeEnum.TYPE_1.getValue(), room.getLiveContentType())) {
//            未开启资金账户
            if (Objects.equals(AccountVerificationEnum.NO_VALIDATE.getValue(),accountVerification)) {
                Token token = TokenThreadLocal.getToken();
//                已经登录有登录信息
                if (Objects.nonNull(token)) {
//                    从登录信息中获取资金账户
                    String custId = token.getCustId();
                    String fundId = token.getFundId();
//                    无资金账户信息 且未进行交易登录
                    if (StrUtil.isBlank(custId) && StrUtil.isBlank(fundId)) {
                        showOpenAccount = 1;
                    }
                }
            }
        }
        return showOpenAccount;
    }

    /**
     * 判断当前登录人员，是否订阅了该房间对应的栏目，如果有订阅，获取栏目基础信息
     */
    private void checkColumnAttention(Token account, InavRoomRespVO liveInfo) {
        Integer columnId = liveInfo.getColumnId();
        Integer accountId = account.getAccountId();
        Boolean subscribe = liveColumnService.isSubscribe(columnId, accountId);
        liveInfo.setColumnAttentionFlag(subscribe);
    }

    private boolean checkInviteCard(String roomId) {
        try {
            GetInviteCardReqVO getInviteCardReqVO = new GetInviteCardReqVO();
            getInviteCardReqVO.setRoomId(roomId);
            GetInviteCardRespVO inviteCard = inviteCardService.getInviteCardNoException(getInviteCardReqVO);
            return inviteCard != null;
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        return false;
    }

    private void setTag(InavRespVO result, RoomsEntityDTO room) {
        if (StringUtils.isNotEmpty(room.getTopics())) {
            // 标签获取
            try {
                List<TagVO> tgs = tagService.listByIds(room.getTopics());
                result.setTags(tgs);
            } catch (Exception ex) {
                Throwable e = ex.getCause();
                if (e instanceof com.netflix.client.ClientException) {
                    // 说明没有当前组件的实现, 即没有选择当前组件
                    log.warn("标签组件未加载:", ex);
                } else {
                    throw ex;
                }
            }
        }
    }

    private void bulidInavRespVOWithAccount(InavRespVO result, InavRoomRespVO liveInfo, Token account, RoomsEntityDTO room, GetInavVO vo) {
        liveInfo.setPhone(Long.parseLong(account.getPhone()));
        liveInfo.setAccsType(account.getAccountType());
        int isVisitor = 0;
        //  判断当前账号是否是游客
        if (account.getAccountType() == RoomConstant.ACCOUNT_TYPE_VISITOR) {
            isVisitor = 1;
        }
        liveInfo.setIsVisitor(isVisitor);
        result.setIsVisitor(isVisitor);
        //目前前端经过改造  vo.getRoleName()已弃用
        //1 主持人 2 观众（默认） 3 嘉宾 4 助理
        Integer roleName = getRolesName(room, vo.getPassword(), vo.getRoleName(), account.getAccountId());
        //AType这个值在嘉宾、助理登录得时候单独设置的值
        if (account.getAType() != null) {
            roleName = account.getAType();
        }
        result.setType(roleName);
        result.setRoleName(roleName);
        result.setThirdPartyUserId(account.getAccountId().longValue());
        //观看权限判断 为null代表是普通观众、嘉宾助理不做并发控制
        if (account.getAType() == null) {
            //检验用户手机号在不在白名单以及账号有没有报名
            boolean canWatch = watchDecide(liveInfo, result);
            //为true 代表账号不在白名单表  或者账号没有报名
            if (canWatch) {
                result.setRoomInfo(liveInfo);
                return;
            }
        }
        startRoomSetCountInfo(result, account, room, roleName);

        //给前端 构造pass得  url请求地址
        String accessTokenUrl = paasService.buildPassUrl(room, account.getAccountId());
        result.setAccessTokenUrl(accessTokenUrl);

        //查询一下 视频回放 是否存在
        checkRecordInfo(room);

        //创建一个  vssToken
        String vssToken = vssTokenService.createToken(account.getAccountId());
        result.setVssToken(vssToken);
        //更新访客记录表
        RoomJoinsEntityDTO join = upsertRoomJoin(account, room, result.getRoleName());
        //如果发现这个人 被 踢出了 房间 不让这人进房间
        if (join.getIsKicked() != null && join.getIsKicked() == 1) {
            throw new BusinessException(BizErrorCode.BIZ_KICKED);
        }
        //踢出状态
        result.setIsKickOut(join.getIsKicked());
        //发言状态
        result.setIsBlockSpeek(join.getIsBanned());
        //设置 url地址
        setChatAndDocUrl(result, vssToken, room.getRoomId(), room.getIlId().toString());
    }

    /**
     * 检查回放 id 是否存在,如果不存在则清空
     *
     * @param room 房间对象
     */
    private void checkRecordInfo(RoomsEntityDTO room) {
        if (StringUtils.isBlank(room.getRecordId())) {
            room.setRecordId("");
        } else {
            RecordEntityDTO record = getRecordExists(room.getRecordId());
            // 音视频资源不存在时设置为空
            if (record == null) {
                room.setRecordId("");
            }
        }
    }

    private void startRoomSetCountInfo(InavRespVO result, Token account, RoomsEntityDTO room, Integer roleName) {
        if (account.getAType() == null) {
            //只有直播中的 直播间 才进行  直播控制
            if (room.getStatus() == RoomConstant.STATUS_START) {
                //为了 防止 直播结束之后
                //  RedisKey.CONNECT_COUNT_BY_ROOM + ilId  这个 房间的redis连接数量没有及时清理  导致 观众无法观看回放
                ConnectJudgeRspVO resp = ctrl(roleName, room, account);
                if (resp != null) {
                    //这两个字段 是方便开发人员看连接数
                    result.setACount(resp.getAppRemain());
                    result.setBCount(resp.getAccountRemain());
                }
            }
            //进行 进入直播间得代码得并发控制  如果应用里面没有 可以直接注释掉
        }
    }

    /**
     * 参考相关文档：https://apaas.vhallyun.com/docs-perfctl
     *
     * @param roleName 角色信息
     * @param room     房间
     * @param account  token信息
     * @return
     */
    private ConnectJudgeRspVO ctrl(Integer roleName, RoomsEntityDTO room, Token account) {
        try {
            // 并发控制
            if (roleName == Integer.parseInt(RoomConstant.AUDIENCE)) {
                ConnectJudgeRspVO resp = ctrlService.judgment(room.getAccountId(), room.getRoomId(),
                        room.getIlId(), room.getChannelId(), account.getThirdPartyUserId() + "", room.getNifyChannel());
                if (resp.getOverload()) {
                    throw new BusinessException(BizErrorCode.BIZ_HOT);
                }
                return resp;
            }
        } catch (Exception ex) {
            Throwable e = ex.getCause();
            if (e instanceof com.netflix.client.ClientException) {
                // 说明没有当前组件的实现, 即没有选择当前组件
                log.warn("并发控制组件未加载:", ex);
            } else {
                throw ex;
            }
        }
        return null;
    }

    @Override
    public Boolean setDocumentStatus(SetDocumentStatusReqVO reqVO) {
        // 1、根据参数中的room_id查询房间信息。
        RoomsEntityDTO room = roomInnerService.getRoomInfo(reqVO.getRoomId());
        if (null == room) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        if (1 == reqVO.getStatus()) {
            Optional.ofNullable(documentsRoomService.getInfo(reqVO.getDocumentId(), null))
                    .orElseThrow(() -> new BusinessException(BizErrorCode.EMPTY_DOCUMENT));
        }

        //清除上一次演示中的文档ID。
        redisTemplate.opsForZSet().removeRangeByScore(RedisKey.ROOM_DOC, room.getIlId(), room.getIlId());
        // 2、获取用户信息
        VssToken token = VssTokenThreadLocal.getToken();
        Integer accountId = token.getThirdPartyUserId();
        RoomJoinsEntityDTO accountInfo = roomInnerService.getRoomJoinsByRoomIdAndThirdId(room.getRoomId(), accountId);
        // 3、判断权限
        if (accountInfo == null || RoomConstant.AUDIENCE.equals(accountInfo.getRoleName())) {
            throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
        }
        redisTemplate.opsForHash().put(RedisKey.ROOM_GLOBAL + room.getRoomId(), RoomConstant.IS_OPEN_DOCUMENT, reqVO.getStatus());
        if (1 == reqVO.getStatus()) {
            //演示中保存文档ID与房间关系，便于控制台删除文档判断使用
            redisTemplate.opsForZSet().add(RedisKey.ROOM_DOC, reqVO.getDocumentId(), room.getIlId());
            redisTemplate.opsForValue().set(RedisKey.ROOM_DOC_INFO + room.getIlId(), reqVO.getDocumentId(), 1, TimeUnit.DAYS);
        } else {
            redisTemplate.delete(RedisKey.ROOM_DOC_INFO + room.getIlId());
            //演示结束，删除缓存
            redisTemplate.opsForZSet().removeRangeByScore(RedisKey.ROOM_DOC, room.getIlId(), room.getIlId());
        }
        return true;
    }

    @Override
    public InavRespVO adminGet(GetInavVO vo) {
        if (StringUtils.isNotEmpty(vo.getRoleName())
                && !vo.getRoleName().equals(RoomConstant.HOST)
                && !vo.getRoleName().equals(RoomConstant.AUDIENCE)) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
        }
        InavRespVO result = new InavRespVO();
        RoomsEntityDTO room = new RoomsEntityDTO();
        // 兼容il_id和room_id
        if (vo.getIlId() != null) {
            String ilId = vo.getIlId().toString();
            room = roomInnerService.getRoomInfoByIlId(ilId);
        }
        if (StringUtils.isNotBlank(vo.getRoomId())) {
            String roomId = vo.getRoomId();
            room = roomInnerService.getRoomInfo(roomId);
        }
        if (room == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        InavRoomRespVO liveInfo = new InavRoomRespVO();
        BeanUtils.copyProperties(room, liveInfo);

        //房间的观看限制为报名模式时，查询数据库中的表单模板
        if (Objects.equals(liveInfo.getLimitType(), 1)) {
            ApplyEntityDTO apply = watchLimitInnerService.getApply(String.valueOf(vo.getIlId()));
            if (apply != null) {
                liveInfo.setFormId(String.valueOf(apply.getSourceId()));
            }
        }
        // 获取水印
        RoomWatermarkDTO roomWatermark = roomService.getRoomWatermark(room.getWatermarkTempId());
        result.setWatermark(roomWatermark);
        //对房间设置标签
        setTag(result, room);
        // 开播时长
        result.setSecond(getSecond(room));
        // 邀请卡状态   如果你得应用里面  没有标签 可以 直接注释掉
        setRoomDetails(room, liveInfo);
        // 暖场视频
        WarmVo warmInfo = getWarmInfo(room.getIlId());
        result.setWarmInfo(warmInfo);
        if (Objects.nonNull(warmInfo) && warmInfo.getType() == 0) {
            liveInfo.setWarmType(0);
            liveInfo.setWarmVodId(null);
        }
        liveInfo.setGiftFrequency(room.getGiftFrequency());
        if (liveInfo.getPageChannelId() != null) {
            //获取频道名称
            PageChannelEntity pageChannelEntity = pageChannelMapper.selectById(liveInfo.getPageChannelId());
            liveInfo.setPageChannelName(pageChannelEntity.getChannelName());
        }
        result.setRoomInfo(liveInfo);

        // 邀请卡状态
        // 如果你得应用里面  没有标签 可以 直接注释掉
        if (checkInviteCard(room.getRoomId())) {
            result.setInviteStatus(1);
        } else {
            result.setInviteStatus(0);
        }
        return result;
    }

    /**
     * 观看限制判断
     *
     * @param liveInfo live info
     * @param result   inav response
     * @return 返回true  账号不在白名单表  或者账号没有报名
     * 返回false 代表可以观看
     */
    private Boolean watchDecide(InavRoomRespVO liveInfo, InavRespVO result) {
        boolean watchCheck = watchCheck(liveInfo, result);
        if (!watchCheck) {
            return false;
        }
        long phone = liveInfo.getPhone();
        Integer ilId = liveInfo.getIlId();

        // https://apaas.vhallyun.com/docs-watch-limit
        //报名模式
        if (Objects.equals(liveInfo.getLimitType(), RoomConstant.LIMITE_TYPE_SIGNUP)) {
            //如果是报名模式 ，游客访问，不做处理直接返回
            if (3 == liveInfo.getAccsType()) {
                liveInfo.setEnroll(0);
                return false;
            }
            //报名模式 且是普通观众，则查询观众手机号是否已经报名
            ApplyUserEntityDTO applyInfo = watchLimitInnerService.getApplyUserByPhoneAndIlId(ilId, phone);
            if (applyInfo == null || applyInfo.getPhone() == null) {
                //代表没有报名  enroll=0  代表没有报名  否则 为1
                liveInfo.setEnroll(0);
                return true;
            }
            liveInfo.setEnroll(1);

        }
        //白名单模式
        else if (Objects.equals(liveInfo.getLimitType(), RoomConstant.LIMITE_TYPE_WHITEACCOUNT)) {
            //1、检查手机号是否在白名单里面
            //白名单模式有单独的登录接口，所以只需校验手机号即可，白名单登录 校验了密码
            WhiteAccountsEntityDTO applyInfo = watchLimitInnerService.getWhiteAccountsByNameAndIlId(ilId, phone);
            if (applyInfo == null || applyInfo.getWhitename() == null) {
                liveInfo.setEnroll(0);
                return true;
            }
            liveInfo.setEnroll(1);
        }
        //游客模式
        else if (Objects.equals(liveInfo.getLimitType(), RoomConstant.LIMITE_TYPE_DEFAULT)) {
            //如果当前账号的账户类型是游客，则对此字段进行赋值
            Integer visitor = liveInfo.getAccsType() == 3 ? 1 : 0;
            liveInfo.setIsVisitor(visitor);
        }
        return false;
    }

    private boolean watchCheck(InavRoomRespVO liveInfo, InavRespVO result) {
        // 1代表主持人
        if (RoomConstant.HOST.equals(liveInfo.getAccsType().toString())) {
            return false;
        }
        //代表 嘉宾  助理
        if (RoomConstant.ASSISTANT.equals(result.getType().toString()) || RoomConstant.INTERACTION.equals(result.getType().toString())) {
            return false;
        }
        // 0 登录模式 1 报名 2 游客模式 3 白名单模式 这 三种报名模式  return true  需要 走后面得  三种模式得检查
        return LIMIT_TYPE.contains(liveInfo.getLimitType());
    }

    private WarmVo getWarmInfo(Integer ilId) {
        Map<String, Object> roomWarmInfo = roomInnerService.getRoomWarmInfo(ilId);
        if (CollectionUtils.isNotEmpty(roomWarmInfo)) {
            return JsonUtil.objectFromJSONString(JsonUtil.toJsonString(roomWarmInfo), WarmVo.class);
        }
        WarmVo info = new WarmVo();
        info.setType(0);
        return info;
    }

    /**
     * 获取直播已播放时长
     *
     * @param room 房间信息
     * @return 播放时长
     */
    private long getSecond(RoomsEntityDTO room) {
        long seconds = 0L;
        if (room.getStatus() == RoomConstant.STATUS_START && null != room.getBeginLiveTime()) {
            LocalDateTime now = LocalDateTime.now();
            Duration duration = Duration.between(room.getBeginLiveTime(), now);
            seconds = duration.toNanos();
        }
        return seconds;
    }


    /**
     * 获取用户进入直播间时所使用角色
     *
     * @param room      房间
     * @param pwd       房间密码
     * @param roleName  角色信息
     * @param accountId 登录用户编号
     * @return role name
     */
    private Integer getRolesName(RoomsEntityDTO room, String pwd, String roleName, long accountId) {
        int accountType = Integer.parseInt(RoomConstant.AUDIENCE);

        //兼容 app端代码  修改 部分
        if (StringUtils.isNotEmpty(pwd)) {
            accountType = getAccountTypeByPwd(room, pwd, accountId, accountType);
        } else {
            // 2. 登录用户token信息判断
            if (accountId == room.getAccountId()) {
                //主持人 role name 有传值且不为主持人 报错
                if (StringUtils.isNotBlank(roleName) && !roleName.equals(RoomConstant.HOST)) {
                    throw new BusinessException(BizErrorCode.AUTH_ROLE_ERROR);
                }
                return Integer.parseInt(RoomConstant.HOST);
            }
            // 3. 前端传入的 role_name 判断
            if (StringUtils.isNotBlank(roleName)) {
                //role_name 有传值且非观众 报错
                if (!roleName.equals(RoomConstant.AUDIENCE)) {
                    throw new BusinessException(BizErrorCode.AUTH_ROLE_ERROR);
                }
                return Integer.parseInt(roleName);
            }
        }
        return accountType;
    }

    private Integer getAccountTypeByPwd(RoomsEntityDTO room, String pwd, long accountId, Integer accountType) {
        if (room.getAccountId() == accountId) {
            throw new BusinessException(BizErrorCode.AUTH_ROLE_ERROR);
        }
        RoomSupplyEntityDTO supply = roomInnerService.getRoomSupplyByIlId(room.getIlId());
        if (supply != null) {
            if (pwd.equals(supply.getAssistantSign())) {
                // 助理
                accountType = Integer.parseInt(RoomConstant.ASSISTANT);
            } else if (pwd.equals(supply.getInteractionSign())) {
                //互动口令
                accountType = Integer.parseInt(RoomConstant.INTERACTION);
            } else {
                throw new BusinessException(BizErrorCode.AUTH_ROLE_PASSWORD_ERROR);
            }
            if (room.getStatus() == RoomConstant.STATUS_STOP) {
                throw new BusinessException(BizErrorCode.AUTH_NOT_SUPPORT_ROLE_PASSWORD);
            }
        }
        return accountType;
    }

    private RecordEntityDTO getRecordExists(String recordId) {
        return recordInnerService.getRecord(recordId);
    }

    private RoomJoinsEntityDTO upsertRoomJoin(Token account, RoomsEntityDTO room, Integer roleName) {
        String profilePhoto = account.getProfilePhoto();
        Integer accountId = account.getAccountId();
        String username = account.getUsername();
        String nickname = account.getNickname();
        return roomInnerService.updateOrInsertRoomJoin(room, profilePhoto, accountId, roleName, username, nickname);
    }

    private void setChatAndDocUrl(InavRespVO respVO, String vssToken, String roomId, String ilId) {
        try {
            String token = Base64.encodeBase64String(vssToken.getBytes(StandardCharsets.UTF_8));
            String webChatUrl = applicationUrl + "/assistant/" + ilId + "?embedType=chat&vssToken=" + token + "&roomId=" + roomId;
            String webDocUrl = applicationUrl + "/assistant/" + ilId + "?embedType=doc&vssToken=" + token + "&roomId=" + roomId;
            respVO.setWebChatUrl(webChatUrl);
            respVO.setWebDocUrl(webDocUrl);
        } catch (Exception e) {
            log.error("set assistant url fail", e);
        }
    }


    private void setRoomDetails(RoomsEntityDTO room, InavRoomRespVO result) {
        result.setIlId(room.getIlId());
        result.setRoomId(room.getRoomId());
        result.setSubject(room.getSubject());
        result.setAccountId(Long.parseLong(room.getAccountId().toString()));
        result.setInavId(room.getInavId());
        result.setChannelId(room.getChannelId());
        result.setNifyChannel(room.getNifyChannel());
        result.setRecordId(room.getRecordId());
        result.setStartTime(room.getStartTime());
        result.setIntroduction(room.getIntroduction());
        result.setCategory(room.getCategory());
        result.setCoverImage(room.getCoverImage());
        result.setImage(room.getCoverImage());
        result.setTopics(room.getTopics());
        result.setLayout(room.getLayout());
        result.setStatus(room.getStatus());
        result.setIsDelete(room.getIsDelete());
        result.setMessageApproval(room.getMessageApproval());
        result.setCreatedAt(room.getCreatedAt());
        result.setUpdatedAt(room.getUpdatedAt());
        result.setAppId(room.getAppId());
        result.setLiveType(room.getLiveType());
        result.setLike(room.getLike());
        result.setWarmType(room.getWarmType());
        result.setWarmVodId(room.getWarmVodId());
        result.setMode(room.getMode());
        result.setIsOpenDocument(room.getIsOpenDocument());
        result.setLimitType(room.getLimitType());
        result.setTeacherName(room.getTeacherName());
        result.setBeginLiveTime(room.getBeginLiveTime());
        result.setEndLiveTime(room.getEndLiveTime());
        result.setBeginTime(room.getStartTime());
        result.setBeginTimeStamp(room.getBeginTimeStamp().longValue());
        result.setDesc(room.getIntroduction());
        // 房间是否开启评论
        // 获取当前房间配置信息
        LambdaQueryWrapper<RoomConfig> where = Wrappers.lambdaQuery();
        where.eq(RoomConfig::getRoomId, room.getRoomId());
        List<RoomConfig> roomConfigs = roomConfigMapper.selectList(where);
        if (CollectionUtils.isNotEmpty(roomConfigs)) {

            Map<String, Integer> integerMap = roomConfigs.stream().collect(Collectors.toMap(RoomConfig::getConfigKey, RoomConfig::getConfigValue, (e1, e2) -> e1));

            result.setReservationStatus(integerMap.get(RoomConfigStatusEnum.RESERVATION_STATUS.getValue()));
            result.setCommentStatus(integerMap.get(RoomConfigStatusEnum.COMMENT_STATUS.getValue()));
            result.setChatManagementLiveStatus(integerMap.get(RoomConfigStatusEnum.CHAT_MANAGEMENT_LIVE.getValue()));
            result.setChatManagementPlaybackStatus(integerMap.get(RoomConfigStatusEnum.CHAT_MANAGEMENT_PLAYBACK.getValue()));
            result.setGiftLiveStatus(integerMap.get(RoomConfigStatusEnum.CHAT_MANAGEMENT_GIFT.getValue()));
        }


    }


}
